#include "rout_lb.h"

int head;
int tail;
int flag = 1; // when 1 has spot, when 0 queue has no spot
int debugmode = 0;
int debugmode2 = 0;
long timeArr[BSIZEINF];
int tokenCounter = 0;
int sendrate = 50;
FILE *inf, *outf;

void delay(int rate) {
	float rateF, delaynsec;
	int delaysec;
	struct timespec tmReq = { 0 }, tmRem = { 0 };
	rateF = (float) rate;
	delaysec = (int) 1 / rateF;
	tmReq.tv_sec = delaysec;
	delaynsec = (float) 1 / rate - delaysec;
	tmReq.tv_nsec = delaynsec * 1000000000L;
	//	printf("in delay1 time %f \n", delaynsec);
	nanosleep(&tmReq, &tmRem);
}

int getsizefrompacket(char* buffer) {
	char temp[SIZELENGTH];
	int size;
	strncpy(temp, buffer + IDLENGTH, SIZELENGTH);
	size = atoi(temp);
	while(size>(SIZELENGTH*10))
		size=size/10;
	return size;
}
int getseqfrompacket(char* buffer) {
	char temp[SEQLENGTH];
	//	printf("here is ur buffer from packet: %s\n", buffer);
	strncpy(temp, buffer + IDLENGTH + SIZELENGTH, SEQLENGTH);
	//	printf("here is ur seq from packet: %d\n", atoi(temp));
	return atoi(temp);
}

int main(void) {
	int iret1, iret2;
	//int iret3;
	char** buffer;
	int bufseq[BSIZEINF];
	int rec_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	int send_sock1 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	int send_sock2 = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
	int i;
	pthread_mutex_t mp = PTHREAD_MUTEX_INITIALIZER;

	pthread_t rece, send;
	//pthread_t tc;
	head = 0;
	tail = 0;
	//new for lock...
	//pthread_mutexattr_t mattr;
	//pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_PRIVATE);
	//pthread_mutex_init(&mp, NULL);
	//lock code end

	inf = fopen("input_time_lb.txt", "w");
	outf = fopen("output_time_lb.txt", "w");

	struct sockaddr_in rec_sa;
	struct sockaddr_in send_sa1;
	struct sockaddr_in send_sa2;

	RECEIVERSTRUCT* rec_input;
	RECEIVERSTRUCT* send_input;

	rec_input = (RECEIVERSTRUCT*) malloc(sizeof(RECEIVERSTRUCT));
	send_input = (RECEIVERSTRUCT*) malloc(sizeof(RECEIVERSTRUCT));

	buffer = (char**) malloc(BSIZEINF * sizeof(char*));
	for (i = 0; i < BSIZEINF; i++)
		buffer[i] = (char*) malloc(FSIZE * sizeof(char)); //FSIZE is the max u can have for one packet

	memset(&rec_sa, 0, sizeof(rec_sa));
	rec_sa.sin_family = AF_INET;
	rec_sa.sin_addr.s_addr = INADDR_ANY;
	rec_sa.sin_port = htons(RECPORT);

	memset(&send_sa1, 0, sizeof(send_sa1));
	send_sa1.sin_family = AF_INET;
	send_sa1.sin_addr.s_addr = INADDR_ANY;
	send_sa1.sin_port = htons(SENDPORT1);

	memset(&send_sa2, 0, sizeof(send_sa2));
	send_sa2.sin_family = AF_INET;
	send_sa2.sin_addr.s_addr = INADDR_ANY;
	//inet_pton(AF_INET, "10.10.1.12", &(send_sa.sin_addr));
	send_sa2.sin_port = htons(SENDPORT2);

	if (-1 == bind(rec_sock, (struct sockaddr *) &rec_sa,
			sizeof(struct sockaddr))) {
		perror("error bind failed in router");
		close(rec_sock);
		exit(EXIT_FAILURE);
	}

	rec_input->socket1 = rec_sock;
	rec_input->saddress1 = &rec_sa;
	rec_input->mainbuffer = buffer;
	//rec_input->mp = &mp;

	send_input->socket1 = send_sock1;
	send_input->saddress1 = &send_sa1;
	send_input->socket2 = send_sock2;
	send_input->saddress2 = &send_sa2;
	send_input->mainbuffer = buffer;
	//send_input->mp = &mp;

	iret1 = pthread_create(&rece, NULL, receiver, (void*) rec_input); //sleep (4);
	iret2 = pthread_create(&send, NULL, sender, (void*) send_input);
	//iret3 = pthread_create(&tc, NULL, tockenCounter, (void*) &mp);

	//iret2 = pthread_create(&leakybucket, NULL, leakybucket, (void*) send_input); //changed to leakybucket instead of sender

	pthread_join(rece, NULL);
	pthread_join(send, NULL);
	//pthread_join(tc, NULL);

	//pthread_join(leakybucket, NULL);

	close(rec_sock);

	return 0;
}

long timestamp() {
	time_t ltime;
	struct timeval ts;
	long timeinms;
	ltime = time(NULL);
	gettimeofday(&ts, NULL);
	timeinms = ts.tv_sec * 1000000 + ts.tv_usec;
	//printf("Here is the time in timeinms: %ld\n", timeinms);
	return timeinms;
}

/*int msleep(unsigned long milisec) {
	struct timespec req = { 0 };
	time_t sec = (int) (milisec / 1000);
	milisec = milisec - (sec * 1000);
	req.tv_sec = sec;
	req.tv_nsec = milisec * 1000000L;
	while (nanosleep(&req, &req) == -1)
		continue;
	return 1;
}*/
/*
void *tockenCounter(void *input) {
	pthread_mutex_t *lock = (pthread_mutex_t*) input;
	while (1) {
		delay(TOKENRATE);
		pthread_mutex_lock(lock);
		if (++tokenCounter > TOKENMAX)
			tokenCounter = TOKENMAX;
		pthread_mutex_unlock(lock);
//		printf("tocken: %d out of %d\n", tokenCounter, TOKENMAX);
	}
}
*/
void *sender(void *input) {
	RECEIVERSTRUCT* inputstruct;
	char buffer[FSIZE];//changed to tokenmax
	//size_t recsize, fromlen;
	int sock1, sock2;
	int buffer_length, bytes_sent;
	char** mainbuffer;
	//int senderCounter = 0;
	//int rec1 = 0, rec2 = 0;
	//long queueDelay = 0;
	//pthread_mutex_t* lock;
	int bflag = 0;
	int pcount = 0;
	int tokenrequired = 0;
	struct sockaddr_in sa1;
	struct sockaddr_in sa2;
	inputstruct = (RECEIVERSTRUCT*) input;
	sock1 = inputstruct->socket1;
	sock2 = inputstruct->socket2;

	sa1 = *(inputstruct->saddress1);
	sa2 = *(inputstruct->saddress2);
	mainbuffer = inputstruct->mainbuffer;
	//lock = inputstruct->mp;

	buffer_length = FSIZE;

	while (1) {
		delay(TOKENRATE);
			if (++tokenCounter > TOKENMAX)
			tokenCounter = TOKENMAX;
		//delay(sendrate);
		if (flag == 1 && tail == head) //empty buffer
			continue;

		if (bflag == 0) {
			strcpy(buffer, mainbuffer[tail]);
			tokenrequired = getsizefrompacket(buffer);
			bflag = 1;
		}
		//pthread_mutex_lock(lock);
		if (bflag == 1 && tokenCounter < tokenrequired) {
			//pthread_mutex_unlock(lock);
			continue;
		}
		tokenCounter -= tokenrequired;
		//pthread_mutex_unlock(lock);
		//queueDelay = timestamp() - timeArr[tail];
		//printf ("Stime: %ld\n", timestamp());
		//printf("%ld\n", queueDelay);

		//pthread_mutex_lock(lock);
		if ((buffer[0] - '0') == DESTINATION1) {
			/*					if (debugmode2) {
			 rec1++;
			 printf("to dest1: %d\n", rec1);
			 }
			 if (debugmode)
			 printf("\n sending to 1\n");*/
			///////////////////////////////////////////////////////
			bytes_sent = sendto(sock1, buffer, buffer_length, 0,
					(struct sockaddr*) &sa1, sizeof(struct sockaddr_in));
			//////////////////////////////////////////////
			/*					if (bytes_sent < 0)
			 printf("Error sending packet: %s\n", strerror(errno));
			 else if (debugmode) {
			 printf("sendsize: %d tail: %d\n ", bytes_sent, tail);
			 printf("datagram: %s\n", buffer);
			 }*/
		} else if ((buffer[0] - '0') == DESTINATION2) {
			/*					if (debugmode2) {
			 rec2++;
			 printf("to dest2: %d\n", rec2);
			 }
			 if (debugmode)
			 printf("\n sending to 2\n");*/
			bytes_sent = sendto(sock2, buffer, buffer_length, 0,
					(struct sockaddr*) &sa2, sizeof(struct sockaddr_in));

			/*					if (bytes_sent < 0)
			 printf("Error sending packet: %s\n", strerror(errno));
			 else if (debugmode) {
			 printf("sendsize: %d tail: %d\n ", bytes_sent, tail);
			 printf("datagram: %s\n", buffer);
			 }*/
		}
		tail = (tail + 1) % BSIZEINF;
		bflag = 0;
		flag = 1;
		pcount++;
		fprintf(outf, "%ld\n", timestamp());
		if (pcount > DFLUSH) {
			fflush(outf);
			pcount = 0;
		}
		//		pthread_mutex_unlock(lock);

		if (debugmode)
			printf("sended frame: %s, new tail: %d\n", buffer, tail);
	}
	close(sock1); // close the socket
	close(sock2);

}

void *receiver(void *input) {
	RECEIVERSTRUCT* inputstruct;
	char buffer[FSIZE];
	size_t recsize, fromlen;
	int sock;
	//int uniqueCounter = 0;
	char** mainbuffer;
	struct sockaddr_in sa;
	//	pthread_mutex_t* lock;
	//int temp;
	int pcount = 0;

	inputstruct = (RECEIVERSTRUCT*) input;
	sock = inputstruct->socket1;
	sa = *(inputstruct->saddress1);
	mainbuffer = inputstruct->mainbuffer;
	//	lock = inputstruct->mp;

	printf("\n recv ....\n");

	while (1) {
		recsize = recvfrom(sock, (void *) buffer, FSIZE, 0,
				(struct sockaddr *) &sa, &fromlen);
		//		printf("recsize in recieve: %d", (int)fromlen);
		//		pthread_mutex_lock(lock);
		if (flag && recsize) {
			pcount++;
			fprintf(inf, "%ld\n", timestamp());
			//			fprintf(stdout, "%ld\n", temp);
			if (pcount > DFLUSH) {
				fflush(inf);
				pcount = 0;
			}
			strcpy(mainbuffer[head], buffer);
			//printf ("Rtime: %ld\n", timestamp());
			//timeArr[head] = timestamp();

			if (debugmode) {
				printf("\n recsize: %d head: %d\n ", recsize, head);
				printf("datagram: %s\n", buffer);
			}
			if ((head = ((head + 1) % BSIZEINF)) == tail)
				flag = 0;
		} else {
			if (head != tail)
				flag = 1;
		}

		//		pthread_mutex_unlock(lock);
		//		if (debugmode)
		//			printf("new head: %d\n", head);
	}
}

